{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 算法链与管道\n",
    "### 通过将Pipeline和GridSearchCV结合,简化数据处理过程"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "#导入相关模块\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "import scipy as sc\n",
    "import matplotlib.pyplot as plt\n",
    "import seaborn as sns\n",
    "import mglearn\n",
    "%matplotlib inline\n",
    "\n",
    "#忽略弹出的warnings\n",
    "import warnings\n",
    "warnings.filterwarnings('ignore')  \n",
    "pd.set_option('display.float_format', lambda x: '%.5f' % x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.988536155203\n"
     ]
    }
   ],
   "source": [
    "#简短代码实现数据划分,数据缩放和模型训练\n",
    "from sklearn.svm import SVC\n",
    "from sklearn.datasets import load_breast_cancer\n",
    "from sklearn.model_selection import train_test_split\n",
    "from sklearn.preprocessing import MinMaxScaler\n",
    "from sklearn.metrics import roc_auc_score \n",
    "\n",
    "#加载缩放数据\n",
    "cancer = load_breast_cancer()\n",
    "scaler_data = MinMaxScaler().fit(cancer.data).transform(cancer.data)\n",
    "\n",
    "#划分数据\n",
    "x_train,x_test,y_train,y_test = train_test_split(scaler_data,cancer.target,random_state=0,test_size=0.3)\n",
    "\n",
    "#构建模型\n",
    "model = SVC().fit(x_train,y_train)\n",
    "\n",
    "#打印AUC分数\n",
    "auc_svc = roc_auc_score(y_test,model.decision_function(x_test))\n",
    "print(auc_svc)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 用预处理进行参数选择"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "最佳交叉验证精度(accurary): 0.977386934673\n",
      "最佳准确率(precision): 0.976608187135\n",
      "最佳参数组合: {'C': 10, 'gamma': 0.1}\n"
     ]
    }
   ],
   "source": [
    "#寻找最佳参数,缺陷:事先将测试数据泄露给模型\n",
    "from sklearn.model_selection import GridSearchCV\n",
    "param_grid = {'C': [0.001, 0.01, 0.1, 1, 10, 100],\n",
    "              'gamma': [0.001, 0.01, 0.1, 1, 10, 100]} #SVM 模型参数组合\n",
    "#重构模型\n",
    "model = GridSearchCV(SVC(),param_grid=param_grid,cv=10).fit(x_train,y_train)\n",
    "\n",
    "#打印\n",
    "print(\"最佳交叉验证精度(accurary):\",model.best_score_)\n",
    "print(\"最佳准确率(precision):\",model.score(x_test,y_test))\n",
    "print(\"最佳参数组合:\",model.best_params_)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n33zzzVrZc845h/Hjx9OtWze6detW7jzOhx9+mCOPPJKuXbuy++67M2zYMJ5++um1HnPVqlVMmDCB\nfv360blzZw499FAeeeSRSue35jlTy5cv5+qrr6Z///506dKFPn36cOGFF/LZZ58BcM011zB06FAA\nJk2aRAiBOXPmVPlzkFR/LFNSHtpnn30A+NOf/sTYsWN54YUXyr1gadasGQceeGC5Q+eaN29Ov379\n+PTTTyvc8D744IOsXr2aQYMGlS5bsGAB77//PjvvvDNt27atck4nnngi++23X+nhOmtq27YthYWF\npeOccMIJFBYWsuWWW66VHTp0KD/+8Y8BOOKII0pfOEiqexvj+qasGCPHH388W2yxBYMHD2arrbZi\n/PjxnHjiiaxevbpcdtasWdx0000MHDiQnj170qVLFwDGjRvHaaedxkcffcSgQYMYNGgQb7zxBsce\neyz33ntvuTHOOeccLrvsMpo0acIRRxxBmzZtOPXUU3nppZeqnevy5cv57W9/y3XXXUfLli058sgj\nCSHwj3/8g2HDhrFs2TL22GOP0p9bly5dyq1XJeWhbDbrl19+1fEXUBBjzFblf/7nf7IFBQWlX7vv\nvnv2hBNOyN58883Z999/v8L7zJ49O1tQUJD9/e9/v9ZtAwcOzO62227ZZcuWlS6bOXNmtqCgIHvS\nSSdVOZf1MWTIkGxBQUF2yZIlpcvuvvvubEFBQfbmm28uXXb22WdnCwoKsvPmzat0rBhjFijI5sHv\nzC+/NtavTXl9UzLfCy+8sHTZypUrs6ecckq2oKAge/fdd6+VnTFjRrkxXnrppWwIITtkyJDsV199\nVbr8s88+y+6///7ZLl26ZD/99NNyz3n48OHZb775pjQ7efLk0vHfeeedco/5y1/+svT7q666KltQ\nUJD94x//mF29enXp8vHjx2cLCgqyf//737PZbDb79NNPZwsKCrIXXXRRlc/fdaRfftX/l3umpDx1\nwQUXcMMNN7DvvvvStGlTli1bxuOPP84ll1xC3759+ctf/rLWu649evSgbdu2TJ8+vdzJy4sWLWLe\nvHkccMABtGjRonT50qVLAcotk9TwbMzrm+bNmzN69OjS75s0acJZZ50FJOdtldWsWbO1Lmpx1113\nkc1mOeuss9hiiy1Kl7du3ZoTTjiB5cuXl16i/MEHHwTgtNNOY7PNNivNDh48mJ133rnauT744IO0\nbNmSMWPGlNvrNmTIEI4//nh++MMfruvTlpQnvJqflMd69+5N7969+fLLL5k7dy6zZ8/mscce4623\n3uLGG29k9erVnHnmmaX5TCbDoYceyvjx43nqqadKXzSUvKAoeyI4wNZbbw3AF198UUfPSFK+2ljX\nNyEEttpqq3LLdtxxR7beemvmz59fbnmbNm1o3LhxuWWvvfYaAI888kjpxThKfPDBBwC8/vrrQHLJ\n8saNG691dVKArl278p///KfSeX799de89dZbdO/enc0337zcbS1atCj3s5W08XDPlLQRaNGiBb16\n9eKcc85h2rRpXHTRRWQyGSZPnszy5cvLZUuOtS95BxWSD8dt27Yte+65Z7lsyYnhb731VrVzeOed\nd9Y6oVvSpmdjW99st912FS7fZpttSveGlWjWrNlauZLMjTfeyLXXXlvu66677gKSS5VDUgQ333zz\nta56CKxV6NZUMkbLli2reUaSNiaWKSnPLFu2jAMOOIARI0ZUeHsmk+Hwww9nn3324euvvy5957RE\n+/btSz/8csWKFbz44ou88847DBgwYK2TuXfaaSd23HFH3nzzTd59990q53XSSSfRvXt3Fi5cuGFP\nUFLe2BTWN5WVri+++GKdPqKhefPmNG7cmFdffZUYY4Vf11xzDQBbbrklX3/9dYWfAfXVV19V+zgA\nX375ZYW3V3d/SfnJMiXlmZYtW7J06VKeeuopPvnkkyqzjRo1Ytttt11r+YABA1i2bBlPPfUURUVF\nAOWuqlVWyfLrr7++0sd58skneeONN9huu+3o2LHjuj6VKq3LVbok1a5NYX3z6quvrnU+17vvvstH\nH31UerW+qoQQWLVqVemhfGW98MILXH755cydOxeAn/70p6xevbrCK/e9+uqrVT5Oq1at2H777Xn9\n9ddLP4+vxIoVK9hnn30YPnw44PpR2phYpqQ8NHjwYFasWMGpp57KRx99tNbtM2bM4KmnnmL//fev\n8JCRgw8+mM0224zHHnuM6dOn87Of/Ywdd9yxwscaPnw4bdu25c477+S6665b6zNjXnnlFc444wwA\nzjzzTBo1qpnVRslhMhW9wyup7mzs65uPP/6YCRMmlH6/cuVKLr30UgB+/etfV3v/koJ38cUXs2zZ\nstLly5Yt44ILLuCmm24qneegQYPIZDJcfvnl5bIPPvhgtWUK4Je//CVLly5d6wOJJ02axFdffcVe\n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\nM888k169erHLLruw++67c+SRRzJt2rR1mtNrr73GyJEj6dGjB507d2bAgAHcfvvtZLPZcrkQAuec\ncw7jx4+nW7dudOvWjYkTJ1Y4ZgiBa6+9FoBTTjmFEAJTp05l8eLF5c6ZOuecczj33HMBuOSSSwgh\nsHjx4nWatyRJqj8e5iepzo0dO5Y77riDPfbYg/3224+lS5fy0EMPcdxxx3HzzTfTo0cPAD7++GOO\nOOII3n33XXr06EG/fv2YN28e48eP56WXXmLChAk0adKEl19+maOPPprNNtuMAw44gO9973u89dZb\nzJgxg1NPPZXx48fz85//vNL5PP744xQWFtK0adPS+8+aNYsLLriAefPmMXbs2HL5WbNmMX36dAYN\nGsQnn3xCly5dKhy3sLCQZ555hmeeeYaDDjqInXfemU6dOq2V69u3L1988QUzZsygZ8+e7Lbbbmy5\n5ZYb8BOWJEl1wTIlqU4tW7aMKVOm0L17d2699dbS5YcffjiHHXYYt912W2mZuuyyy3j33Xc599xz\nOeaYY0qzf/jDH/i///s/HnvsMQ444ADGjRvHt99+y9SpU+nYsWNp7qGHHuL000/ngQceqLRMLV++\nnHPOOYeWLVty55130q5dOwDOOOMMTjvtNKZMmULfvn3p1atX6X0++eQTrr/+evr06VPlcx01ahTX\nXHMNzzzzDAcffDB9+/YFWGuvU9kyte+++5Z7rpIkKX9ZpiTVqdWrV5PNZnnvvfd4//332X777QHY\nddddefTRR2nTpg2QnGs0ffp02rdvv1a5GDFiBK1bt2bbbbcF4JhjjuHXv/51uSIFlJayTz/9tNL5\nPPbYY3z22WecddZZpUUKoFGjRowZM4Zp06Zx9913lytTzZo1K/e9JElqmCxTkurUlltuyUEHHcSD\nDz7I/vvvT9euXdlvv/34+c9/zg9/+MPS3Ntvv81XX33FbrvtttYYbdu25fTTTy/9ft999wWSwwLn\nz5/P22+/TXFxMc899xwAq1atqnQ+r776KpCcM3XNNdesdXvjxo2ZP39+uWVt2rShcePG6/GsJUnS\npsgyJanO/elPf2KXXXZh6tSppecUXX755eyyyy5cdNFFdOrUiSVLlgDQsmXLasd7//33GTt2LI89\n9hjZbJZGjRrRvn17fvazn5VemrwyS5cuBeDBBx+sNFMylxLNmjWrdk6SJGnTZ5mSVOeaNm3K8OHD\nGT58OO+99x5PPvkkRUVFPPHEE4wYMYIZM2bQokULgLWu2lfiq6++onnz5mSzWU488UTeeOMNRowY\nQd++ffnRj35Es2bN+OSTT7jzzjurnEvz5s0BmDhxInvttVfNPlFJkrRJ89LokurUO++8wxVXXMG/\n/vUvAHbYYQcOP/xw/va3v7Hnnnvy4YcfsnjxYjp06EDTpk15+eWX1xrjww8/pGvXrpx//vnEGFmw\nYAH7778/p59+OrvuumvpnqNFixYBrHV587JCCMB3h/uV9fnnn/PHP/6Re++9d4Ofd3UymUytP4Yk\nSapZlilJdapZs2bcdNNNjBs3rvQDbSG54MTHH3/MZpttxrbbbsvmm29Ov379WLRo0Vp7l8aPHw/A\nXnvtxWabbQasfZGJzz//nD//+c9A8rlWldl///1p2bIlEyZMoLi4uNxtl112GZMmTeLtt99O/4TX\nUZMmyYECK1eurPXHkiRJNcPD/CTVqW233ZZhw4Zx8803c8ghh9CrVy8aNWrErFmzWLRoESNHjiw9\nT+qss87iueee47zzzmPatGn86Ec/4pVXXuHZZ5+lb9++HHTQQaxevZrOnTszd+5cjjrqKHbffXf+\n+9//8uijj7JixQq22GIL/vvf/1Y6ny233JKLLrqIM844g0GDBtG3b1++//3v88wzz/DKK6+w6667\nMnz48Fr/uWy33XYA3H777SxZsoSjjz66dJkkScpP7pmSVOfOPPNMLrjgAlq2bMk///lPpkyZQosW\nLbj00ksZPXp0aW677bbjzjvv5IgjjiDGyKRJk3jvvfc4+eSTufLKK4HkEuZ//etf+dWvfsXixYu5\n9dZbmTt3Lvvttx933303++yzD2+++WaVe5cOPPBAJk+ezJ577smsWbOYPHkyX375JSNHjmTixIml\n52/Vpu7duzN48GCWLFnCbbfdVnqIoiRJyl+Zqs4lkKQ0MplMQYwxFhQU1PdUNikLFiwghBCy2eyC\n+p6LJElyz5QkSZIkpWKZkiRJkqQULFOSJEmSlIJlSpIkSZJSsExJkiRJUgqWKUmSJElKwTIlSZIk\nSSlYpiRJkiQphSb1PQFJm6bi4uL6nsImx5+pJEn5JZPNZut7DpI2MZlMpjHQsb7nsY62yH19Vt8T\nWUeLstnsqvqehCRJskxJauAymcwTQGdg+2w2+2V9z0eSJG08PGdKUkPXHmgFtK7neUiSpI2MZUqS\nJEmSUrBMSZIkSVIKlilJkiRJSsEyJUmSJEkpWKYkSZIkKQXLlCRJkiSl0KQ2Bs1kMnsBh9TG2JJU\nw9rm/vxjJpNZXK8zkaTqvZjNZu+s70lIStTKh/ZmMpn5QKjxgSVJkhq2LLBtNpv9tL4nIqmW9kwB\nLXN/XgYsqaXHkKSasDuwA/AmFyXkAAAgAElEQVRAfU9EkqpxNsmHjG9R3xORlKitPVOLSQ6d+UE2\nm/WwGUmSpA3k6ysp/3gBCkmSJElKobbK1BfAauCrWhpfkiSpofH1lZRnauucqSHADtls9rNaGl+S\nJKmh8fWVlGdq5ZwpSZIkSdrUec6UJEmSJKVgmZIkSZKkFCxTkiRJkpSCZUqSJEmSUrBMSZIkSVIK\nlilJkiRJSsEyJUmSJEkpWKYkSZIkKQXLlCRJkiSlYJmSJEmSpBQsU5IkSZKUgmVKkiRJklKwTEmS\nJElSCpYpSZIkSUrBMiVJkiRJKTRZ12Amk2kMdKzFuUiSpJqzKJvNrir5xu14g1D6O/f3La2XcuvL\n9bHOZQroWFRUFDt06FDhjXPmzGH06NGMGzeOHj16VDuYefPmzZs3b7528sXFxfTv3z8AC8pEOw4Z\nMiQuW7aMoqIi+vfvT7t27aodf/HixeY3gvznn3/O5MmTy/7OOw4ZMiRuvfXW1T6G1JBV8H9nvWSy\n2ey6BTOZghhjLCgoWOu2mTNncvjhh3PnnXfSu3fvascyb968efPmzddefsGCBYQQQjabLX1xkMlk\nCgYOHBgfeeQRDj/8cCp7c7Ss4uJi7rzzTvMbQf6TTz7h2muvLf2dZzKZgsLCwrjNNttU+zhSQ7bm\n/531tcHnTG0sGxbz5s2bN2++IecBioqK8uKFv/mazy9evLjajKSat0FlKt82FObNmzdv3rz5yvXv\n3z8vXvibr/l8UVFRtTlJNS91mcq3DYV58+bNmzdvvmrrco5OPhYF89Xn+/fvX21WUs1bnwtQlMq3\nDYV58+bNmzdvfsPla1EwX32+VatW1eYl1bz13jOVbxsK8+bNmzdv3vyGy+eiYH7D85Jqx3qVqTlz\n5uTVhsK8efPmzZs3v7Y5c+ZUmykr3174m6/ZvKTas16H+Y0ePZqpU6fmxYbCvHnz5s2bN19xfvTo\n0dXmSuTbC3/zNZuXVLvWa8/UuHHj8mZDYd68efPmzZuvOD9u3Lhqs5B/L/zN12xeUu1brz1T6/JJ\n7Pm6YTFv3rx58+YbSn6HHXaoNp9vL/zN12xeUt1Yrz1T1cnnDYt58+bNmzdvPpFvL/zN12xeUt2p\nsTKVbxsK8+bNmzdv3vza8u2Fv/mazUuqW6k+Z2pN+bahMG/evHnz5s2vbfHixTzyyCN588LffM3m\nJdW9Dd4zlW8bCvPmzZs3b958xYqKivLmhb/5ms0vXry42oykmrdBZSrfNhTmzZs3b968+cr1798/\nL174m6/5fFFRUbU5STUvdZnKtw2FefPmzZs3b75q7dq1qzaTj0XBfPX5/v37V5uVVPNSnTOVbxsK\n8+bNmzdv3vyGy9eiYL76fKtWrarNS6p5671nKt82FObNmzdv3rz5DZfPRcH8hucl1Y71KlNz5szJ\nqw2FefPmzZs3b35tc+bMqTZTVr698Ddfs3lJtWe9DvMbPXo0U6dOzYsNhXnz5s2bN2++4vzo0aOr\nzZXItxf+5ms2L6l2rdeeqXHjxuXNhsK8efPmzZs3X3F+3Lhx1WYh/174m6/ZvKTat157pnr06FFt\nJl83LObNmzdv3nxDye+www7V5vPthb/5ms1LqhvrtWeqOvm8YTFv3rx58+bNJ/Lthb/5ms1Lqjs1\nVqbybUNh3rx58+bNm19bvr3wN1+zeUl1K9XnTK0p3zYU5s2bN2/evPm1LV68mEceeSRvXvibr9m8\npLq3wXum8m1DYd68efPmzZuvWFFRUd688Ddfs/nFixdXm5FU8zaoTOXbhsK8efPmzZs3X7n+/fvn\nxQt/8zWfLyoqqjYnqealLlP5tqEwb968efPmzVetXbt21WbysSiYrz7fv3//arOSal6qc6bybUNh\n3rx58+bNm99w+VoUzFefb9WqVbV5STVvvfdM5duGwrx58+bNmze/4fK5KJjf8Lyk2rFee6buuece\nLr30UsaNG8cOO+zAggULqszPmTOH0aNHmzdv3rx58+brMH/PPfdUuPzzzz+vcPnixYspKiqif//+\ntGrVik8++aTK8c3nX76i321lv29J39nQ/yeZbDa7bsFMpjHQcYMeTZIk1ZVF2Wx2Vck3bscbhNLf\nub9vab2UW1+uj3UuU5JqRghhN6BVjHFWyvu/CVwUY5ywDtkssH+M8dE0j1XN2MOAK0j2cO8YY1xS\nRXYi0CTGOKSS2xcD58UYJ9b0PCXlnxDCMSTrsXYhhN7Av4CmMcZvK8heBPSMMfZeh3E3A46NMd6Q\n+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\n3r3p2LEj/fv35+abb+azzz4rk1u5ciWXXXYZPXv25LDDDuPII4/k9NNPZ9asWdvVpldeeYULL7yQ\nrl270rFjR0455RQeeugh4jguk4uiiLFjxzJp0iQ6d+5M586duffeeytcZxRFTJw4EYCf//znRFHE\njBkzKC4uLnPN1NixY7niiisA+N3vfkcURRQXF29XuyVJUsNxmJ+kenf11Vfz8MMPc/TRR3Pcccex\nYcMGnnjiCX76059yzz330LVrVwA++ugjBg8ezLvvvkvXrl3p378/K1asYNKkSSxdupTJkyfTqFEj\nli1bxplnnkmTJk3o168f3/jGN3jrrbeYO3cuF198MZMmTeL444+vtD1///vfGTFiBI0bN868fsGC\nBYwbN44VK1Zw9dVXl8kvWLCAp556ioEDB7J27Vo6depU4XpHjBjBc889x3PPPceJJ57IQQcdxKGH\nHlou16dPH9avX8/cuXPp0aMHhx9+OC1btqzFT1iSJNUHiylJ9Wrjxo088sgjdOnShfvvvz+zfNCg\nQZx22mk88MADmWLq+uuv59133+WKK67g7LPPzmR//etf8+c//5l58+bRr18/JkyYwFdffcWMGTNo\n3759JvfEE09wySWX8L//+7+VFlObNm1i7NixtGjRgmnTprH//vsDcOmllzJq1CgeeeQR+vTpQ8+e\nPTOvWbt2LXfccQe9e/eu8rNedNFF3HrrrTz33HOcdNJJ9OnTB6DcWafSxdSxxx5b5rNKkqT8ZTEl\nqV5t3bqVOI557733WLNmDfvuuy8AHTp0YM6cObRu3RpIrjV66qmnaNu2bbniYvjw4ey1117ss88+\nAJx99tn86Ec/KlNIAZmi7OOPP660PfPmzWPdunWMGTMmU0gB7LLLLowePZpZs2Yxffr0MsVU06ZN\ny3wvSZJ2ThZTkupVy5YtOfHEE5k5cyZ9+/bliCOO4LjjjuP444/n29/+dib39ttv8/nnn3P44YeX\nW0ebNm245JJLMt8fe+yxQDIs8LXXXuPtt99m9erVvPDCCwBs2bKl0vYsX74cSK6ZuvXWW8s9X1BQ\nwGuvvVZmWevWrSkoKKjBp5YkSTsiiylJ9e66667jsMMOY8aMGZlrim644QYOO+wwxo8fz6GHHsqn\nn34KQIsWLapd35o1a7j66quZN28ecRyzyy670LZtW4466qjM1OSV2bBhAwAzZ86sNFPSlhJNmzat\ntk2SJGnHZzElqd41btyYYcOGMWzYMN577z2eeeYZioqKePrppxk+fDhz586lefPmAOVm7Svx+eef\n06xZM+I45vzzz+eNN95g+PDh9OnTh4MPPpimTZuydu1apk2bVmVbmjVrBsC9997LMccck9sPKkmS\ndmhOjS6pXr3zzjvcdNNN/O1vfwNgv/32Y9CgQdx9991069aNDz74gOLiYtq1a0fjxo1ZtmxZuXV8\n8MEHHHHEEfzqV78ihMDKlSvp27cvl1xyCR06dMicOVq1ahVAuenNS4uiCPjvcL/SPvnkE37729/y\n2GOP1fpzVyeVStX5e0iSpNyymJJUr5o2bcpdd93FhAkTMje0hWTCiY8++ogmTZqwzz77sOuuu9K/\nf39WrVpV7uzSpEmTADjmmGNo0qQJUH6SiU8++YTf//73QHJfq8r07duXFi1aMHnyZFavXl3mueuv\nv54pU6bw9ttvZ/+Bt1OjRslAgS+//LLO30uSJOWGw/wk1at99tmHs846i3vuuYfvf//79OzZk112\n2YUFCxawatUqLrzwwsx1UmPGjOGFF17gyiuvZNasWRx88MG8/PLLPP/88/Tp04cTTzyRrVu30rFj\nR5YsWcJPfvITjjzySP79738zZ84cNm/ezG677ca///3vStvTsmVLxo8fz6WXXsrAgQPp06cP3/zm\nN3nuued4+eWX6dChA8OGDavzn0urVq0AeOihh/j0008588wzM8skSVJ+8syUpHp32WWXMW7cOFq0\naMFf/vIXHnnkEZo3b861117LyJEjM7lWrVoxbdo0Bg8eTAiBKVOm8N577/Gzn/2Mm2++GUimML/9\n9tv54Q9/SHFxMffffz9LlizhuOOOY/r06XTv3p0333yzyrNLJ5xwAlOnTqVbt24sWLCAqVOn8tln\nn3HhhRdy7733Zq7fqktdunThjDPO4NNPP+WBBx7IDFGUJEn5K1XVtQSSlI1UKlUYQgiFhYUN3ZQd\nysqVK4miKIrjeGVDt0WSJHlmSpIkSZKyYjElSZIkSVmwmJIkSZKkLFhMSZIkSVIWLKYkSZIkKQsW\nU5IkSZKUBYspSZIkScqCxZQkSZIkZaFRQzdA0o5p9erVDd2EHY4/U0mS8ksqjuOGboOkHUwqlSoA\n2jd0O3ZQq+I43tLQjZAkSRZTknZyqVRqKFAYx/GVDd0WSZL09WIxJWmnlkql3gQOBPaN4/j9Bm6O\nJEn6GnECCkk7u0bb/CtJkrRdLKYkSZIkKQsWU5IkSZKUBYspSZIkScqCxZQkSZIkZcFiSpIkSZKy\nUGezV6Vv2ilJ+a5kW1XgdkvS18DW2PvaSHmjTu4zlUql7gaG5XzFkiRJO7elQJc4jr9s6IZIqrti\nqhhoA8TphyTlq9LDnbc2WCskqXol26tvxXFc3KAtkQTU/U0qD/A/uyRJUu2VOlgtKU84AYUkSZIk\nZcFiSpIkSZKyUFfD/P4fcBTwfh2tX5IkaWfj/pWUZ+pkAgpJkiRJ2tE5zE+SJEmSsmAxJUmSJElZ\nsJiSJEmSpCxYTEmSJElSFiymJEmSJCkLFlOSJEmSlAWLKUmSJEnKgsWUJEmSJGXBYkqSJEmSsmAx\nJUmSJElZsJiSJEmSpCxYTEmSJElSFiymJEmSJCkLFlOSJEmSlAWLKUmSJEnKQqPtDaZSqQKgfR22\nRZIk5c6qOI63lHxjP75TyPzO/X1LNVJme1kT211MAe1btmwZJk6cSNeuXasNL168mJEjRzJhwgTz\n5s2bN2/efD3mR4wYwfr16yNgZamn2g8ZMiTsueeeZfLFxcUUFRUxYMAA9t9//2rXbz4/85988glT\np04t/Tuv8PctqawK/u/USCqO4+0LplKFU6ZMCWeeeWa12fnz5zNo0CCmTZtGr169zJs3b968efP1\nmL/pppsYOnRoFMdxZucglUoVjhgxIuy9996Z/OrVq5k2bRqDBg2iXbt21a7ffP7m165dy8SJEzO/\n84p+35LK2/b/Tk3V5MzUdh0Ry9eOxbx58+bNm99Z8vvtt1+1+a9ToWC+5nlJ9SOnE1Dkc8di3rx5\n8+bNm0/k246/+dzmJdWfnBVT+dZRmDdv3rx58+bLy7cdf/O5zUuqXzUa5leZfOsozJs3b968efPl\nFRcXM3v27LzZ8Tef27yk+lfrM1P51lGYN2/evHnz5itWVFSUNzv+5nObLy4urjYjKfdqVUzlW0dh\n3rx58+bNm6/cgAED8mLH33zu80VFRdXmJOVe1sVUvnUU5s2bN2/evPmqbc99jPKxUDBffX7AgAHV\nZiXlXlbXTOVbR2HevHnz5s2br718LRTMV5/ffffdq81Lyr0an5nKt47CvHnz5s2bN197+VwomK99\nXlLdqFExtXjx4rzqKMybN2/evHnz5S1evLjaTGn5tuNvPrd5SXWnRsP8Ro4cyYwZM/KiozBv3rx5\n8+bNV5wfOXJktbkS+bbjbz63eUl1q0ZnpiZMmJA3HYV58+bNmzdvvuL8hAkTqs1C/u34m89tXlLd\nq9GZqa5du1abydeOxbx58+bNm99Z8vvtt1+1+Xzb8Tef27yk+lGjM1PVyeeOxbx58+bNmzefyLcd\nf/O5zUuqPzkrpvKtozBv3rx58+bNl5dvO/7mc5uXVL+yus/UtvKtozBv3rx58+bNl1dcXMzs2bPz\nZsfffG7zkupfrc9M5VtHYd68efPmzZuvWFFRUd7s+JvPbb64uLjajKTcq1UxlW8dhXnz5s2bN2++\ncgMGDMiLHX/zuc8XFRVVm5OUe1kXU/nWUZg3b968efPmq7b//vtXm8nHQsF89fkBAwZUm5WUe1ld\nM5VvHYV58+bNmzdvvvbytVAwX31+9913rzYvKfdqfGYq3zoK8+bNmzdv3nzt5XOhYL72eUl1o0bF\n1OLFi/OqozBv3rx58+bNl7d48eJqM6Xl246/+dzmJdWdGg3zGzlyJDNmzMiLjsK8efPmzZs3X3F+\n5MiR1eZK5NuOv/nc5iXVrRqdmZowYULedBTmzZs3b968+YrzEyZMqDYL+bfjbz63eUl1r0Znprp2\n7VptJl87FvPmzZs3b35nye+3337V5vNtx998bvOS6keNzkxVJ587FvPmzZs3b958It92/M3nNi+p\n/uSsmMq3jsK8efPmzZs3X16+7fibz21eUv3K6j5T28q3jsK8efPmzZs3X15xcTGzZ8/Omx1/87nN\nS6p/tT4zlW8dhXnz5s2bN2++YkVFRXmz428+t/ni4uJqM5Jyr1bFVL51FObNmzdv3rz5yg0YMCAv\ndvzN5z5fVFRUbU5S7tVomN/q1aszXy9evJiRI0cyYcIE9ttvP1auXFnla82bN2/evHnz9ZMv3V+X\n1qJFC9auXVvl+ouLiykqKmLAgAHsvvvu5r8m+R49ejBnzpwyz33yySdVvlZS7f+fpOI43r5gKlUA\ntK/Vu0mSpPqyKo7jLSXf2I/vFDK/c3/fUo2U2V7WxHYXU5JyI4qiw4HdQwgLsnz9m8D4EMLk7cjG\nQN8Qwpzqslm04yzgJpIz3AeEED6tInsv0CiEMKSS54uBK0MI9+a6nZLyTxRFZ5Nsx/aPoqgX8Deg\ncQjhqwqy44EeIYRe27HeJsA5IYQ/pr+fDzwdQrgyd63PvFd/4B6gJdAthLC8iuw4oE8IoUclzz8N\n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\n",
      "text/plain": [
       "<Figure size 1080x720 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "mglearn.plots.plot_improper_processing() #缺陷:事先将测试数据泄露给模型"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 构建管道"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "AUC分数: 0.988536155203\n"
     ]
    }
   ],
   "source": [
    "from sklearn.svm import SVC\n",
    "from sklearn.datasets import load_breast_cancer\n",
    "from sklearn.model_selection import train_test_split\n",
    "from sklearn.preprocessing import MinMaxScaler\n",
    "from sklearn.metrics import roc_auc_score \n",
    "from sklearn.pipeline import Pipeline\n",
    "\n",
    "#加载划分数据\n",
    "cancer = load_breast_cancer()\n",
    "x_train,x_test,y_train,y_test = train_test_split(cancer.data,cancer.target,random_state=0,test_size=0.3)\n",
    "\n",
    "#构建管道\n",
    "pipe=Pipeline([(\"scaler\",MinMaxScaler()),(\"svm\",SVC())]) #同时实现数据缩放和分类器构建\n",
    "\n",
    "pipe.fit(x_train,y_train)\n",
    "\n",
    "#打印AUC\n",
    "auc_svc = roc_auc_score(y_test,pipe.decision_function(x_test))\n",
    "print(\"AUC分数:\",auc_svc)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 在网络搜索中使用管道"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "最佳交叉验证精度(accurary): 0.979899497487\n",
      "最佳准确率(precision): 0.970760233918\n",
      "最佳参数组合: {'svm__C': 100, 'svm__gamma': 0.1}\n"
     ]
    }
   ],
   "source": [
    "from sklearn.model_selection import GridSearchCV\n",
    "\n",
    "\n",
    "param_grid = {'svm__C': [0.001, 0.01, 0.1, 1, 10, 100],\n",
    "             'svm__gamma': [0.001, 0.01, 0.1, 1, 10, 100]} #SVM 模型参数组合\n",
    "\n",
    "#重构模型\n",
    "model = GridSearchCV(pipe,param_grid=param_grid,cv=5).fit(x_train,y_train)\n",
    "\n",
    "#打印\n",
    "print(\"最佳交叉验证模型精度(accurary):\",model.best_score_)\n",
    "print(\"最佳准确率(precision):\",model.score(x_test,y_test))\n",
    "print(\"最佳参数组合:\",model.best_params_)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 通用的管道接口"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def fit(self,X,y):\n",
    "    \"\"\"模型函数\"\"\"\n",
    "    X_transformed = X\n",
    "    for name,estimator in self.steps[:-1]:\n",
    "        #遍历除了最后一步之外的所有步骤\n",
    "        #对数据进行拟合和变频\n",
    "        X_transformed = estimator.fit_transform(X_transformed,y)\n",
    "        #对最后一步进行拟合\n",
    "        self.steps[-1][1].fit(X_transformed,y)\n",
    "        return self\n",
    "    \n",
    "def predict(self,X):\n",
    "    \"\"\"预测函数\"\"\"\n",
    "    X_transformed = X\n",
    "    for name,estimator in self.steps[:-1]:\n",
    "        #遍历除了最后一步之外的所有步骤\n",
    "        #对数据进行拟合和变频\n",
    "        X_transformed = estimator.fit_transform(X_transformed,y)\n",
    "        #利用最后一步进行预测\n",
    "        return self.steps[-1][1].predict(X_transformed)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[('standardscaler-1', StandardScaler(copy=True, with_mean=True, with_std=True)), ('pca', PCA(copy=True, iterated_power='auto', n_components=2, random_state=None,\n",
      "  svd_solver='auto', tol=0.0, whiten=False)), ('standardscaler-2', StandardScaler(copy=True, with_mean=True, with_std=True))]\n"
     ]
    }
   ],
   "source": [
    "#例子\n",
    "from sklearn.preprocessing import  StandardScaler\n",
    "from sklearn.decomposition import PCA\n",
    "from sklearn.pipeline import make_pipeline\n",
    "\n",
    "pipe = make_pipeline(StandardScaler(),PCA(n_components=2),StandardScaler())\n",
    "print(pipe.steps)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(2, 30)"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#访问管道属性\n",
    "pipe.fit(cancer.data)\n",
    "#提取主成分\n",
    "pipe.named_steps[\"pca\"].components_.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 网络搜索选择使用哪个模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "最佳参数: {'classifier': SVC(C=10, cache_size=200, class_weight=None, coef0=0.0,\n",
      "  decision_function_shape='ovr', degree=3, gamma=0.01, kernel='rbf',\n",
      "  max_iter=-1, probability=False, random_state=None, shrinking=True,\n",
      "  tol=0.001, verbose=False), 'classifier__C': 10, 'classifier__gamma': 0.01, 'preprocessing': StandardScaler(copy=True, with_mean=True, with_std=True)}\n",
      "最佳模型精度: 0.985915492958\n",
      "最佳泛化能力: 0.979020979021\n"
     ]
    }
   ],
   "source": [
    "#到底选择SVM模型还是randomForestClassirer模型或者是逻辑回归模型\n",
    "\n",
    "#导入三个分类器\n",
    "from sklearn.ensemble import RandomForestClassifier\n",
    "from sklearn.svm import SVC\n",
    "from sklearn.linear_model import LinearRegression\n",
    "\n",
    "#导入并划分数据\n",
    "from sklearn.model_selection import train_test_split\n",
    "from sklearn.datasets import load_breast_cancer\n",
    "\n",
    "cancer = load_breast_cancer()\n",
    "X_train, X_test, y_train, y_test = train_test_split(\n",
    "    cancer.data, cancer.target, random_state=0)\n",
    "\n",
    "#构建管道\n",
    "from sklearn.pipeline import Pipeline\n",
    "pipe = Pipeline([(\"preprocessing\",StandardScaler()),(\"classifier\",SVC())])\n",
    "\n",
    "#构建网络搜索参数组合\n",
    "param_grid = [{\"classifier\":[SVC()],\"preprocessing\":[StandardScaler(),None],\n",
    "              \"classifier__gamma\":[0.001,0.01,0.1,1,10,100],\n",
    "              \"classifier__C\": [0.001,0.01,0.1,1,10,100]},\n",
    "             {\"classifier\" : [RandomForestClassifier(n_estimators=100)],\n",
    "             \"preprocessing\":[None],\"classifier__max_features\":[1,2,3]},\n",
    "             {\"classifier\":[LinearRegression()],\"preprocessing\":[StandardScaler(),None]}]\n",
    "\n",
    "#实现网络搜索\n",
    "from sklearn.model_selection import GridSearchCV\n",
    "model_select = GridSearchCV(pipe,param_grid=param_grid,cv=5).fit(X_train,y_train)\n",
    "\n",
    "#打印\n",
    "print(\"最佳参数:\",model_select.best_params_)\n",
    "print(\"最佳模型精度:\",model_select.best_score_)\n",
    "print(\"最佳泛化能力:\",model_select.score(X_test,y_test))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
